package com.ruoyi.file.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <h1>Description.</h1>
 * <p>
 * the vaip file util.
 * It's a long story, so I don't want to tell...
 * </p>
 *
 * @version 2018.3.2
 * @since jdk_1.8.0_144
 */
public class VaipFileUtil {

    private static Log logger = LogFactory.getLog(VaipFileUtil.class);
    private static final int BUFFER_SIZE = 16 * 1024;
    private final static String TXT_SUFFIX = ".txt,.doc,.docx,.html,.sql,.htm,.pdf";
    private final static String VIDEO_SUFFIX = ".mp4";
    private final static String AUDIO_SUFFIX = ".mp3,*.wav";
    private final static String PICTURE_SUFFIX = ".jpg,.jpeg,.bmp,.png,.gif";
    private final static String PDF_SUFFIX = ".pdf";

    public boolean exists(String filepath) {
        return new File(filepath).exists();
    }

    public boolean isTextFile(String fileName) {
        String suffix = null;
        if (null != fileName && fileName.lastIndexOf(".") >= 0) {
            suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        } else {
            return false;
        }

        suffix = suffix.toLowerCase();
        if (TXT_SUFFIX.indexOf(suffix) >= 0 && suffix.length() >= 3) {
            return true;
        }
        return false;
    }

    public boolean isVideoFile(String fileName) {
        String suffix = null;
        if (null != fileName && fileName.lastIndexOf(".") >= 0) {
            suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        } else {
            return false;
        }

        suffix = suffix.toLowerCase();
        if (VIDEO_SUFFIX.indexOf(suffix) >= 0 && suffix.length() > 3) {
            return true;
        }
        return false;
    }

    public boolean isAudioFile(String fileName) {
        String suffix = null;
        if (null != fileName && fileName.lastIndexOf(".") >= 0) {
            suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        } else {
            return false;
        }

        suffix = suffix.toLowerCase();
        if (AUDIO_SUFFIX.indexOf(suffix) >= 0 && suffix.length() >= 3) {
            return true;
        }
        return false;
    }

    public boolean isPicture(String fileName) {
        String suffix = null;
        if (null != fileName && fileName.lastIndexOf(".") >= 0) {
            suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        } else {
            return false;
        }

        suffix = suffix.toLowerCase();
        // the suffix should be greater than 3 to avoid .p/.b/.j file.
        if (PICTURE_SUFFIX.indexOf(suffix) >= 0 && suffix.length() >= 3) {
            return true;
        }
        return false;
    }

    public boolean isPDF(String fileName) {
        String suffix = null;
        if (null != fileName && fileName.lastIndexOf(".") >= 0) {
            suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        } else {
            return false;
        }

        suffix = suffix.toLowerCase();
        if (PDF_SUFFIX.indexOf(suffix) >= 0) {
            return true;
        }
        return false;
    }

    public void makeDir(String dir) {
        File dirFile = new File(dir);
        dirFile.mkdirs();
    }

    public String makeDailyDir(String dir) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = df.format(new Date());
        String year = dateStr.substring(0, 4);
        String month = dateStr.substring(5, 7);
        String day = dateStr.substring(8, 10);

        StringBuilder ndir = new StringBuilder(64);
        if (null != dir) {
            ndir.append(dir);
            if (!dir.endsWith(File.separator)) {
                ndir.append(File.separator);
            }
            ndir.append(year);
            ndir.append(File.separator);
            ndir.append(month);
            ndir.append(File.separator);
            ndir.append(day);
        }

        File nFile = new File(ndir.toString());
        nFile.mkdirs();
        String path = nFile.getAbsolutePath();
        return path;
    }

    public String getFileName(String filepath) {
        if (null == filepath) {
            return null;
        }

        String fileName = null;
        File file = new File(filepath);
        if (file.exists()) {
            fileName = file.getName();
        } else {
            if (filepath.lastIndexOf("\\") > 0) {
                fileName = filepath.substring(filepath.lastIndexOf("\\") + 1);
                return fileName;
            }

            if (filepath.lastIndexOf("/") > 0) {
                fileName = filepath.substring(filepath.lastIndexOf("/") + 1);
                return fileName;
            }
        }
        return fileName;
    }

    public String getFileNameWithoutSuffix(String filepath) {
        if (null == filepath) {
            return null;
        }

        String fileName = null;
        File file = new File(filepath);
        if (file.getName().lastIndexOf(".") > 0) {
            fileName = file.getName().substring(0, file.getName().lastIndexOf("."));
        } else {
            fileName = file.getName();
        }
        return fileName;
    }

    public String getFileDir(String filepath) {
        if (null == filepath) {
            return filepath;
        }

        String filedir = null;
        File file = new File(filepath);
        if (file.exists()) {
            filedir = file.getParent();
        } else {
            filedir = filepath.substring(0, filepath.lastIndexOf(File.separator));
        }
        return filedir;
    }

    public String getFileDirWithFileName(String filepath) {
        if (null == filepath) {
            return null;
        }

        File file = new File(filepath);
        if (!file.exists()) {
            return null;
        } else {
            String nPath = filepath.substring(0, filepath.lastIndexOf("."));
            File nDir = new File(nPath);
            if (!nDir.exists()) {
                nDir.mkdirs();
            }
            return nPath;
        }
    }

    /**
     * 把数据写至文件中。
     *
     * @param filePath 文件路径。
     * @param data     String类型数据内容。
     */
    public void writeFile(String filePath, String data) {
        FileOutputStream fos = null;
        OutputStreamWriter writer = null;
        try {
            fos = new FileOutputStream(new File(filePath));
            writer = new OutputStreamWriter(fos, "UTF-8");
            writer.write(data);
        } catch (Exception ex) {
            logger.error(ex, ex.fillInStackTrace());
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (Exception e) {
            }
        }
    }

    /**
     * 读取文件内容。
     *
     * @param filePath 文件路径。
     * @return String 文件内容。
     */
    public String readFile(String filePath) {
        StringBuffer buffer = new StringBuffer();
        // 读出这个文件的内容。
        try {
            File file = new File(filePath);
            FileInputStream fis = null;
            BufferedReader breader = null;
            try {
                fis = new FileInputStream(file);
                InputStreamReader isReader = new InputStreamReader(fis, "UTF-8");
                breader = new BufferedReader(isReader);
                String line;
                while ((line = breader.readLine()) != null) {
                    buffer.append(line);
                    buffer.append("\r\n");
                }
                breader.close();
                isReader.close();
                fis.close();

            } catch (FileNotFoundException e) {
                logger.error(e.getMessage());
            } catch (IOException e) {
                logger.error(e, e.fillInStackTrace());
            }
        } catch (Exception e) {
            logger.error(e, e.fillInStackTrace());
        }
        return buffer.toString();
    }

    /**
     * 复制文件
     *
     * @param src 被复制的文件。
     * @param dst 复制文件。
     */
    public void copyFile(File src, File dst) {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE);
            out = new BufferedOutputStream(new FileOutputStream(dst), BUFFER_SIZE);
            byte[] buffer = new byte[BUFFER_SIZE];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * copy file.
     *
     * @param originalFilePath the original file you want to copy.
     * @param targetDirPath    the target directory you want to copy the file to.
     * @param covered          if the file existed already, if the program covers
     *                         the file or not.
     */
    public int copyFile(String originalFilePath, String targetDirPath, boolean covered) {
        File originalFile = new File(originalFilePath);
        File targetDir = new File(targetDirPath);

        int count = 0;
        boolean beforeCheck = null != originalFile && originalFile.exists();
        if (beforeCheck) {
            String fileName = originalFile.getName();
            if (!targetDir.exists()) {
                targetDir.mkdirs();
            }
            String newFilePath = targetDir.getAbsolutePath() + File.separator + fileName;
            File newFile = new File(newFilePath);
            if (newFile.exists()) {
                if (covered) {
                    newFile.delete();
                    this.copyFile(originalFile, newFile);
                    count++;
                }
            } else {
                this.copyFile(originalFile, newFile);
                count++;
            }
        }
        return count;
    }

    /**
     * 获取文件名的前缀
     *
     * @param fileName 文件名称。
     * @return String 文件名前缀。
     */
    public String getFilePrefix(String fileName) {
        int splitIndex = fileName.lastIndexOf(".");
        if (splitIndex == -1)
            return "";
        else
            return fileName.substring(0, splitIndex);
    }

    /**
     * 获取文件名的后缀, e.g: a file called, C:/test/test.txt; the method would return .txt.
     *
     * @param name 文件名称。
     * @return String 文件名后缀。
     */
    public String getSuffix(String name) {
        int splitIndex = name.lastIndexOf(".");
        if (splitIndex == -1)
            return null;
        else
            return name.substring(splitIndex).toLowerCase();
    }

    /**
     * 删除文件。
     *
     * @param fileAbsolutePath 文件名称。
     */
    public void deleteFile(String fileAbsolutePath) {
        this.remove(fileAbsolutePath);
    }

    /**
     * 删除文件。
     *
     * @param fileAbsolutePath 文件名称。
     */
    public void remove(String fileAbsolutePath) {
        if (null != fileAbsolutePath) {
            File file = new File(fileAbsolutePath);
            if (file.exists()) {
                file.delete();
            }
        }
    }

    /**
     * 创建文件目录。
     *
     * @param dir 文件目录路径。
     */
    public boolean mkDir(String dir) {
        File file = new File(dir);
        if (!file.exists()) {
            return file.mkdirs();
        }
        return true;
    }

    /**
     * 压缩为.zip文件。
     *
     * @param filename     文件名称。
     * @param tempFilePath 压缩文件路径。
     */
    public void zipFile(String filename, String tempFilePath) throws Exception {
        FileOutputStream fos = null;
        ZipOutputStream zipOut = null;
        File zipFileTemp = new File(filename);
        String[] files = (new File(tempFilePath)).list();
        try {
            fos = new FileOutputStream(zipFileTemp);
            zipOut = new ZipOutputStream(fos);
            int i = 0;
            for (i = 0; i < files.length; i++) {
                File f = new File(files[i]);
                FileInputStream fis = new FileInputStream(tempFilePath + "/" + files[i]);
                ZipEntry ze = new ZipEntry(f.getName());
                zipOut.putNextEntry(ze);
                int c = 0;
                while ((c = fis.read()) != -1) {
                    zipOut.write(c);
                }
                fis.close();
            }
        } finally {
            if (null != zipOut) {
                zipOut.close();
            }
            if (null != fos) {
                fos.close();
            }
        }

    }

    /**
     * 删除文件夹下的所有文件。
     *
     * @param filePath 文件路径。
     */
    public void delAllFile(String filePath) {
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        String dirPath = null;
        if (fileList != null) {
            for (int i = 0; i < fileList.length; i++) {
                if (fileList[i].isFile()) {
                    fileList[i].delete();
                }
                if (fileList[i].isDirectory()) {
                    dirPath = fileList[i].getPath();
                    delAllFile(dirPath);
                }
            }
        }
        file.delete();
    }

    /**
     * 在同一个目录下，如果存放文件时，文件名称相同，则已如下规则“a.pdf”,"a_1.pdf","a_2.pdf"。
     *
     * @param dictoryFile 目标目录
     * @param compareFile 存放的文件
     * @return String 文件名。
     */
    public String getReToName(File dictoryFile, File compareFile) {
        List<Integer> sameFileNameList = new java.util.ArrayList<Integer>();
        String fileFullName = compareFile.getName();
        // String[] fileNameAndSuffix=fileFullName.split("\\.");
        String fileName = fileFullName.substring(0, fileFullName.length() - 4);
        String reToFileName = null;
        if (compareFile.exists()) {
            // 如果文件已经存在。
            File[] fileList = dictoryFile.listFiles();
            for (File tmpFile : fileList) {
                String tmpfileName = tmpFile.getName();
                if (tmpfileName.startsWith(fileName + "_")) {
                    // String tmpFileNameAndSuffix[]=tmpfileName.split("\\.");
                    String tempFilePuffix = tmpfileName.substring(0, tmpfileName.length() - 4);
                    String index = tempFilePuffix.substring(fileName.length() + 1);
                    Integer indexInteger = Integer.valueOf(index);
                    sameFileNameList.add(indexInteger);
                }
            }
            if (sameFileNameList.size() > 0) {
                Collections.sort(sameFileNameList);
                // 获取已存在的最大值。
                Integer maxIndex = sameFileNameList.get(sameFileNameList.size() - 1);
                reToFileName = fileName + "_" + (maxIndex + 1);
            } else {
                // 没有的话从1开始取，eg：a_1.pdf
                reToFileName = fileName + "_1";
            }
        } else {
            reToFileName = fileName;
        }
        // 返回文件名加后缀。
        return reToFileName + ".pdf";
    }

    /**
     * 获取文件创建时间方法
     *
     * @param fullFileName 文件路径。
     * @return String 文件创建时间。
     */
    public String getCreatedTime(String fullFileName) {
        Path path = Paths.get(fullFileName);
        BasicFileAttributeView basicview = Files.getFileAttributeView(path, BasicFileAttributeView.class,
                LinkOption.NOFOLLOW_LINKS);
        BasicFileAttributes attr;
        try {
            attr = basicview.readAttributes();
            Date createDate = new Date(attr.creationTime().toMillis());
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String formatEnDate = format.format(createDate);
            return formatEnDate;
        } catch (Exception e) {
            e.printStackTrace();
        }
        Calendar cal = Calendar.getInstance();
        cal.set(1970, 0, 1, 0, 0, 0);
        Date date = cal.getTime();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formatEnDate = format.format(date);
        return formatEnDate;
    }

    public byte[] covertToByteArray(InputStream instream) {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        byte[] inputData = null;
        int rc = 0;
        try {
            while ((rc = instream.read(buff, 0, 1024)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            inputData = swapStream.toByteArray();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (null != instream) {
                try {
                    instream.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                    e.printStackTrace();
                }
            }
        }
        return inputData;
    }

    public InputStream covertToInputStream(byte[] buf) {
        InputStream instream = new ByteArrayInputStream(buf);

        return instream;
    }

    public void covertToFile(byte[] buf, String filePath, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            if (!dir.exists() && dir.isDirectory()) {
                dir.mkdirs();
            }
            file = new File(filePath + File.separator + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(buf);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void saveFile(InputStream instream, File nfile) {
        byte[] buffer = new byte[1024];
        int length = -1;
        OutputStream outstream = null;
        try {
            outstream = new FileOutputStream(nfile);
            while ((length = instream.read(buffer)) != -1) {
                outstream.write(buffer, 0, length);
            }
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                if (null != instream) {
                    instream.close();
                }
                if (null != outstream) {
                    outstream.close();
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    public String changeTo(String filePath, String suffix) {
        String newPath = null;
        if (suffix.startsWith(".")) {
            newPath = filePath.substring(0, filePath.lastIndexOf(".")) + suffix;
        } else {
            newPath = filePath.substring(0, filePath.lastIndexOf(".")) + "." + suffix;
        }
        return newPath;
    }
}
